package basisService

import (
	"context"
	"fmt"
	"github.com/Sir-yuChen/funAnalyse/global"
	"github.com/Sir-yuChen/funAnalyse/global/constant"
	"github.com/Sir-yuChen/funAnalyse/model"
	"github.com/Sir-yuChen/funAnalyse/model/common/ApiReturn"
	"github.com/Sir-yuChen/funAnalyse/model/request"
	"github.com/Sir-yuChen/funAnalyse/service/autoCode"
	"github.com/Sir-yuChen/funAnalyse/service/commonService"
	"github.com/Sir-yuChen/funAnalyse/utils"
	"go.uber.org/zap"
	"math/rand"
	"strings"
	"time"
)

type CommonService struct{}

func NewCommonService() *CommonService {
	return &CommonService{}
}

// CheckVerificationCode 校验验证码
func (s *CommonService) CheckVerificationCode(r *request.VerificationCodeRequest) (a ApiReturn.ApiReturnCode) {
	var b bool
	var redisFistKey string
	if r.CustomerName != "" {
		var user model.StockUser
		err := global.GVA_DB.Model(&model.StockUser{}).Where("customer_name=?", r.CustomerName).First(&user).Error
		if err != nil {
			redisFistKey = r.IpAddr
		} else {
			redisFistKey = user.CustomerId
		}
	} else {
		redisFistKey = r.IpAddr
	}
	code := global.GVA_REDIS.HGet(context.Background(), redisFistKey, "verification").Val()
	lastType := global.GVA_REDIS.HGet(context.Background(), redisFistKey, "type").Val()
	if lastType != r.Type {
		return ApiReturn.ErrVerificationCode
	}
	if code == r.VerificationCode {
		b = true
	}
	switch r.Type {
	case constant.VER_CODE_RAND:
		if b {
			return ApiReturn.OK
		}
		return ApiReturn.ErrVerificationCode
	case constant.VER_CODE_MOBILE:
		if r.MobileNo == "" {
			return ApiReturn.ErrParam
		}
		if b {
			mobileNos := global.GVA_REDIS.HGet(context.Background(), redisFistKey, constant.VER_CODE_MOBILE).Val()
			split := strings.Split(mobileNos, ",")
			redisStr := split[len(split)-1]
			if redisStr == r.MobileNo {
				return ApiReturn.OK
			}
		}
		return ApiReturn.ErrVerificationCode
	case constant.VER_CODE_EMAIL:
		if r.Email == "" {
			return ApiReturn.ErrParam
		}
		if b {
			emails := global.GVA_REDIS.HGet(context.Background(), redisFistKey, constant.VER_CODE_EMAIL).Val()
			split := strings.Split(emails, ",")
			redisStr := split[len(split)-1]
			if redisStr == r.Email {
				return ApiReturn.OK
			}
		}
		return ApiReturn.ErrVerificationCode
	}
	return ApiReturn.ErrSystem
}

// GetVerificationCode 获取验证码	rand/mobile/email
func (s *CommonService) GetVerificationCode(r *request.VerificationCodeRequest) (a ApiReturn.ApiReturnCode) {
	var conut int
	var redisFistKey string
	redisKey := r.Type + "Count"
	if r.CustomerName != "" {
		var user model.StockUser
		err := global.GVA_DB.Model(&model.StockUser{}).Where("customer_name=?", r.CustomerName).First(&user).Error
		if err != nil {
			redisFistKey = r.IpAddr
		} else {
			redisFistKey = user.CustomerId
		}
	} else {
		redisFistKey = r.IpAddr
	}
	ex, err := global.GVA_REDIS.HExists(context.Background(), redisFistKey, redisKey).Result()
	if err != nil {
		return ApiReturn.ErrSystem
	}
	if ex {
		conut, err = global.GVA_REDIS.HGet(context.Background(), redisFistKey, redisKey).Int()
		if err != nil {
			return ApiReturn.ErrSystem
		}

		switch r.Type {
		case constant.VER_CODE_RAND:
			if conut >= 10 {
				return ApiReturn.VerificationNoCount
			}
			break
		case constant.VER_CODE_MOBILE:
			mobileNos := global.GVA_REDIS.HGet(context.Background(), redisFistKey, constant.VER_CODE_MOBILE).Val()
			if find := strings.Contains(mobileNos, r.MobileNo); find {
				if conut >= 10 {
					return ApiReturn.VerificationNoCount
				}
			} else {
				global.GVA_REDIS.HSet(context.Background(), redisFistKey, constant.VER_CODE_MOBILE, mobileNos+","+r.MobileNo)
			}
			break
		case constant.VER_CODE_EMAIL:
			emails := global.GVA_REDIS.HGet(context.Background(), redisFistKey, constant.VER_CODE_EMAIL).Val()
			if find := strings.Contains(emails, r.Email); find {
				if conut >= 10 {
					return ApiReturn.VerificationNoCount
				}
			} else {
				global.GVA_REDIS.HSet(context.Background(), redisFistKey, constant.VER_CODE_EMAIL, emails+","+r.Email)
			}
			break
		}
	}
	//计数
	global.GVA_REDIS.HSet(context.Background(), redisFistKey, redisKey, conut+1)
	var verCode string
	switch r.Type {
	case constant.VER_CODE_RAND:
		//如果是随机验证码则 生产存redis
		verCode = fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
		break
	case constant.VER_CODE_MOBILE:
		if r.MobileNo == "" {
			return ApiReturn.ErrParam
		}
		//生成验证码 正常调手机短信接口 这里使用随机数模拟
		verCode = fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
		mobileNos := global.GVA_REDIS.HGet(context.Background(), redisFistKey, constant.VER_CODE_MOBILE).Val()
		if mobileNos != "" {
			split := strings.Split(mobileNos, ",")
			redisStr := split[len(split)-1]
			if redisStr != r.MobileNo {
				global.GVA_REDIS.HSet(context.Background(), redisFistKey, constant.VER_CODE_MOBILE, mobileNos+","+r.MobileNo)
			}
		} else {
			global.GVA_REDIS.HSet(context.Background(), redisFistKey, constant.VER_CODE_MOBILE, r.MobileNo)
		}
		break
	case constant.VER_CODE_EMAIL:
		if r.Email == "" {
			return ApiReturn.ErrParam
		}
		//生成验证码 正常调发邮件接口 这里使用随机数模拟 todo
		verCode = fmt.Sprintf("%06v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))

		emails := global.GVA_REDIS.HGet(context.Background(), redisFistKey, constant.VER_CODE_EMAIL).Val()
		if emails != "" {
			split := strings.Split(emails, ",")
			redisStr := split[len(split)-1]
			if redisStr != r.MobileNo {
				global.GVA_REDIS.HSet(context.Background(), redisFistKey, constant.VER_CODE_EMAIL, emails+","+r.Email)
			}
		} else {
			global.GVA_REDIS.HSet(context.Background(), redisFistKey, constant.VER_CODE_EMAIL, r.Email)
		}
		break
	}
	if conut == 1 || conut == 0 {
		timer := time.Duration(60*60) * time.Second
		b := global.GVA_REDIS.Expire(context.Background(), redisFistKey, timer).Val()
		if b == false {
			return ApiReturn.ErrSystem
		}
	}
	//存redis
	global.GVA_REDIS.HSet(context.Background(), redisFistKey, "verification", verCode)
	global.GVA_REDIS.HSet(context.Background(), redisFistKey, "type", r.Type)
	ok := ApiReturn.OK
	var re = make(map[string]interface{})
	re["count"] = conut + 1
	re["verificationCode"] = verCode
	ok.Data = re
	return ok
}

// AutoCode 代码生成器
func (s *CommonService) AutoCode(r *request.AutoCodeRequest) (a ApiReturn.ApiReturnCode) {
	codeStruct := utils.AutoCodeStruct{
		AutoCodePattern: r.Pattern,
		PkgName:         r.Pkg,
		TableName:       r.TableName,
		HasTimer:        false,
		Fields:          nil,
	}
	service := autoCode.NewAutoCodeService()
	structs := []*utils.AutoCodeStruct{
		&codeStruct,
	}
	if r.AutoType == "init" {
		//使用初始化模式
		codeStruct.TableName = ""
		codeStruct.AutoCodePattern = "-1"
	} else {
		//非初始化模式 指定生成表格
		tableName := r.TableName
		if strings.Contains(tableName, ",") {
			if strings.Contains(r.Pattern, "-1") {
				global.GVA_LOG.Error("代码生成初始化参数异常,指定多模式生成文件，模式不能为-1")
				return ApiReturn.ErrParam
			}
			//指定生成不止一张表的代码
			tableNameSplit := strings.Split(tableName, ",")
			patternSplit := strings.Split(r.Pattern, ",")
			pkgSplit := strings.Split(r.Pkg, ",")
			if len(tableNameSplit) != len(patternSplit) || len(patternSplit) != len(pkgSplit) {
				global.GVA_LOG.Error("代码生成初始化参数异常,指定生成表与模式、包结构不匹配")
				return ApiReturn.ErrParam
			}
			for i, v := range tableNameSplit {
				s := utils.AutoCodeStruct{
					AutoCodePattern: patternSplit[i],
					PkgName:         pkgSplit[i],
					TableName:       v,
					HasTimer:        false,
					Fields:          nil,
				}
				structs = append(structs, &s)
			}

		}
	}
	err := service.CreateFileByTpl(structs)
	if err != nil {
		return ApiReturn.ErrSystem
	}
	a = ApiReturn.OK
	return a
}

// GetStockApiResource 获取资源
func (s *CommonService) GetStockApiResource(req *model.StockApiResource) (a ApiReturn.ApiReturnCode) {
	var mo []model.StockApiResource
	sql := ""
	obj := model.NewStockApiResourceModel()
	tableName := obj.TableName()
	sqlCondition := utils.ReflectHandleStuct(req)
	if sqlCondition != "" {
		sql = `select * from ` + tableName + ` where ` + sqlCondition
	} else {
		sql = `select * from ` + tableName + ` order by id desc  limit 100 `
	}
	err := global.GVA_DB.Raw(sql).Scan(&mo).Error
	if err != nil {
		global.GVA_LOG.Error("资源 Get异常", zap.Any("req", req), zap.Any("sql", sql), zap.Error(err))
		return ApiReturn.ErrSystem
	}
	a = ApiReturn.OK
	if len(mo) == 0 {
		a = ApiReturn.NoData
	} else {
		//将数组转json
		a.Data = mo
	}
	return a
}

func (s *CommonService) GetStockTableStructure(r *request.TableStructure) ApiReturn.ApiReturnCode {
	return commonService.GetStockTableStructure(r.TableName)
}
